﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.IO;
using LostLib.Programs.Properties;

namespace LostLib.Programs.WinForms
{
	public partial class ProgramsWinForm : Form
	{
		public ProgramsWinForm()
		{
			InitializeComponent();
		}

		protected override void OnShown(EventArgs e)
		{
			base.OnShown(e);

			if (!AssemblyManager.Installed && (MessageBox.Show(
				"Can't find assembly cache. Do you want to create one in " + Settings.Default.AssemblyCache + "?",
				"It seems that program is not installed",
				MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes))
			{
				Directory.CreateDirectory(Settings.Default.AssemblyCache);
				AssemblyManager.CreateDatabase();

				if (MessageBox.Show(this, "Do you want to add default source http://lostmsu.broker.freenet6.net/CliPack/AssemblyDB.xml?\nWARNING! This source currently needs IPv6 connectivity to the Internet.",
					"Adding sources", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
				{
					AssemblyManager.AddSource("default", "http://lostmsu.broker.freenet6.net/CliPack/AssemblyDB.xml");

					if (MessageBox.Show(this, "Update default source?", "Adding sources", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
					{
						AssemblyManager.UpdateSource("default");

						AssemblyManager.RebuildSuitableVersionList();
					}

					AssemblyManager.ApplicationDatabase.SubmitChanges();
				}
			}

			if (!AssemblyManager.Installed)
			{
				Close();

				return;
			}

			dataSources.AutoGenerateColumns = false;
			dataSources.DataSource = AssemblyManager.ApplicationDatabase.AssemblySources.GetNewBindingList();
			dataAssemblies.AutoGenerateColumns = false;
			dataAssemblies.DataSource = AssemblyManager.ApplicationDatabase.AssemblyInfos.GetNewBindingList();

			lastTab = tabSources;

			wfInstallApprover = new EventHandler<ApproveEventArgs<IEnumerable<AssemblyVersion>>>(AssemblyManager_InstallApprover);
			wfRemoveApprover = new EventHandler<ApproveEventArgs<IEnumerable<AssemblyVersion>>>(AssemblyManager_RemoveApprover);

			AssemblyManager.InstallApprover += wfInstallApprover;
			AssemblyManager.RemoveApprover += wfRemoveApprover;
		}

		EventHandler<ApproveEventArgs<IEnumerable<AssemblyVersion>>> wfInstallApprover;
		EventHandler<ApproveEventArgs<IEnumerable<AssemblyVersion>>> wfRemoveApprover;

		void AssemblyManager_RemoveApprover(object sender, ApproveEventArgs<IEnumerable<AssemblyVersion>> e)
		{
			var msgBuilder = new StringBuilder("Do you want to remove the following assemblies: \n");
			foreach (var assembly in e.Subject)
				msgBuilder.AppendFormat("\t{0}\n", assembly);

			var message = msgBuilder.ToString();

			e.Approved = MessageBox.Show(this, message, "Approve removing", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes;
		}

		void AssemblyManager_InstallApprover(object sender, LostLib.ApproveEventArgs<IEnumerable<AssemblyVersion>> e)
		{
			var msgBuilder = new StringBuilder("Do you want to install the following assemblies: \n");
			foreach (var assembly in e.Subject)
				msgBuilder.AppendFormat("\t{0}\n", assembly);
			var message = msgBuilder.ToString();

			e.Approved = MessageBox.Show(this, message, "Approve installation", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes;
		}

		#region GAC
		AssemblyName[] gac;

		private void tabGAC_DoubleClick(object sender, EventArgs e)
		{
			this.Enabled = false;
			labelGacAction.Text = "Refreshing GAC contents...";
			Application.DoEvents();
			gac = GlobalAssemblyCache.GetAssemblies(false).ToArray();

			dataGAC.AutoGenerateColumns = false;
			dataGAC.DataSource = gac;

			labelGacAction.Text = "Click here to refresh list";
			this.Enabled = true;
		}
		#endregion GAC

		private void tabs_DoubleClick(object sender, EventArgs e)
		{
			if (tabs.SelectedTab == tabGAC)
			{
				tabGAC_DoubleClick(sender, e);
				return;
			}
		}

		#region Sources
		private void buttonSourcesApply_Click(object sender, EventArgs e)
		{
			AssemblyManager.ApplicationDatabase.SubmitChanges();
			dataAssemblies.DataSource = AssemblyManager.ApplicationDatabase.AssemblyInfos.GetNewBindingList();
		}

		private void dataSources_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
		{
			var column = dataSources.Columns[e.ColumnIndex];
			var row = dataSources.Rows[e.RowIndex];
			if (row.IsNewRow) return;

			if (!CheckSourceChanges()) return;

			AssemblyManager.ApplicationDatabase.SubmitChanges();
			var source = row.DataBoundItem as AssemblySource;
			try
			{
				AssemblyManager.UpdateSource(source.Name);
			} catch (FileNotFoundException fileNotFound)
			{
				MessageBox.Show(this, fileNotFound.Message, "Can't update source", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		private bool CheckSourceChanges()
		{
			var changes = AssemblyManager.ApplicationDatabase.GetChangeSet();
			if (changes.Deletes.Count != 0 || changes.Inserts.Count != 0 || changes.Updates.Count != 0)
			{
				switch (MessageBox.Show(this, "Do you want to commit changes you made? " + changes.ToString(), "Committing changes on sources",
					MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
				{
				case DialogResult.Yes:
					AssemblyManager.ApplicationDatabase.SubmitChanges();
					break;
				case DialogResult.No:
					throw new NotImplementedException();
				case DialogResult.Cancel:
					return false;
				}
			}

			return true;
		}
		#endregion

		#region Assemblies
		private void dataAssemblies_CellContentClick(object sender, DataGridViewCellEventArgs e)
		{
			var column = dataAssemblies.Columns[e.ColumnIndex];
			var row = dataAssemblies.Rows[e.RowIndex];
			var assembly = row.DataBoundItem as AssemblyInfo;
			if (assembly.State == AssemblyState.Latest)
			{
				AssemblyManager.Remove(assembly.InstalledVersion);

				return;
			}
			if (assembly.LatestSuitable == null)
			{
				row.Cells[e.ColumnIndex].ErrorText = "no suitable version found";

				return;
			}
			AssemblyManager.Install(new AssemblyVersionFilter[] { new AssemblyVersionFilter { AssemblyName = assembly.AssemblyName, Version = assembly.LatestSuitable.Version } });
		}

		private void dataAssemblies_CellMouseEnter(object sender, DataGridViewCellEventArgs e)
		{
			if (e.RowIndex < 0)
				return;

			var row = dataAssemblies.Rows[e.RowIndex];
			var assembly = row.DataBoundItem as AssemblyInfo;
			var info = "Installed: " + (assembly.InstalledVersion == null? "-": assembly.InstalledVersion.Version.ToString()) + '\n' +
				"Suitable: " + (assembly.LatestSuitable == null? "-": assembly.LatestSuitable.Version.ToString());

			toolTips.SetToolTip(dataAssemblies, info);
			labelVersionInfo.Text = info;
		}
		#endregion Assemblies

		TabPage lastTab;

		private void tabs_Selected(object sender, TabControlEventArgs e)
		{
			if (tabs.SelectedTab == lastTab) return;
			if (lastTab == tabSources)
			{
				if (!CheckSourceChanges())
				{
					tabs.SelectedTab = tabSources;
				}
			}
		}

		private void buttonRemoveDatabase_Click(object sender, EventArgs e)
		{
			if (MessageBox.Show(this, "Do you really want to remove database?\n(This will close this application)", "Removing database", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
			{
				AssemblyManager.ApplicationDatabase.DeleteDatabase();

				Close();
			}
		}

		private void textSearch_KeyDown(object sender, KeyEventArgs e)
		{
			switch (e.KeyCode)
			{
			case Keys.Enter:
				if (tabs.SelectedTab == tabAssemblies)
				{
					foreach (DataGridViewRow row in dataAssemblies.Rows)
					{
						
					}
				}
				break;
			}
		}
	}
}
